﻿import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D


def linear_core_function(z, theta, b):
    # az1+bz2+cz3+...+b
    return np.dot(z, theta) + b


def sigmoid(z):
    return 1 / (1 + np.exp(-z))


def img_2_1_1():
    # 定义参数
    w1, w2 = 1.0, -1.0  # 输入到隐藏层的权重
    b_hidden = 0.5  # 隐藏层的偏置
    w_hidden_output = 1.0  # 隐藏层到输出的权重
    b_output = 0.0  # 输出层的偏置

    # 定义输入数据范围
    x1_range = np.linspace(-6, 6, 100)
    x2_range = np.linspace(-6, 6, 100)
    x1, x2 = np.meshgrid(x1_range, x2_range)

    # 计算隐藏层输入
    hidden_input = w1 * x1 + w2 * x2 + b_hidden

    # 计算隐藏层输出（经过 sigmoid 激活）
    hidden_layer_output = sigmoid(hidden_input)

    # 计算最终输出
    output = w_hidden_output * hidden_layer_output + b_output

    # 绘制三维图形
    fig = plt.figure(figsize=(10, 7))
    ax = fig.add_subplot(111, projection="3d")

    # 绘制输出的三维平面
    ax.plot_surface(x1, x2, output, cmap="viridis", alpha=0.7)

    # 添加决策平面（输出为 0 的等高线）
    ax.contour3D(x1, x2, output, levels=[0.5], colors="red")  # Sigmoid 函数的中点是 0.5

    # 设置标签和标题
    ax.set_xlabel("x1")
    ax.set_ylabel("x2")
    ax.set_zlabel("Output")
    ax.set_title("3D Decision Boundary with Sigmoid Activation")

    plt.show()


def img_2_2_1():
    # 定义参数
    # 输入到隐藏层的权重和偏置
    w1_hidden1, w2_hidden1 = 1.2, -1.0
    w1_hidden2, w2_hidden2 = -1.0, 0.4
    b_hidden1, b_hidden2 = 0.5, -0.5

    # 隐藏层到输出层的权重和偏置
    w_hidden1_output, w_hidden2_output = 1.2, 0.3
    b_output = 0.0

    # 定义输入数据范围
    x1_range = np.linspace(-6, 6, 100)
    x2_range = np.linspace(-6, 6, 100)
    x1, x2 = np.meshgrid(x1_range, x2_range)

    # 计算隐藏层输入
    hidden_input1 = w1_hidden1 * x1 + w2_hidden1 * x2 + b_hidden1
    hidden_input2 = w1_hidden2 * x1 + w2_hidden2 * x2 + b_hidden2

    # 计算隐藏层输出（经过 sigmoid 激活）
    hidden_output1 = sigmoid(hidden_input1)
    hidden_output2 = sigmoid(hidden_input2)

    # 计算最终输出
    output = (
        w_hidden1_output * hidden_output1 + w_hidden2_output * hidden_output2 + b_output
    )

    # 绘制三维图形
    fig = plt.figure(figsize=(10, 7))
    ax = fig.add_subplot(111, projection="3d")

    # 绘制输出的三维平面
    ax.plot_surface(x1, x2, output, cmap="viridis", alpha=0.7)

    # # 添加决策平面（输出为 0.5 的等高线）
    # ax.contour3D(x1, x2, output, levels=[0.5], colors='red')

    # 设置标签和标题
    ax.set_xlabel("x1")
    ax.set_ylabel("x2")
    ax.set_zlabel("Output")
    ax.set_title("3D Decision Boundary with 2 Hidden Nodes")

    plt.show()


def img_2_4_1():
    # 定义参数
    # 输入到隐藏层的权重和偏置
    w1_hidden = [1.1, -1.2, 0.6, -0.8]
    w2_hidden = [-0.8, 1.2, -0.7, 0.1]
    b_hidden = [0.25, -0.45, 0.12, -0.72]

    # 隐藏层到输出层的权重和偏置
    w_hidden_output = [0.75, 0.95, 0.15, 0.25]
    b_output = 0.0

    # 定义输入数据范围
    x1_range = np.linspace(-6, 6, 100)
    x2_range = np.linspace(-6, 6, 100)
    x1, x2 = np.meshgrid(x1_range, x2_range)

    # 计算隐藏层输出（经过 sigmoid 激活）
    hidden_outputs = []
    for i in range(4):
        hidden_input = w1_hidden[i] * x1 + w2_hidden[i] * x2 + b_hidden[i]
        hidden_output = sigmoid(hidden_input)
        hidden_outputs.append(hidden_output)

    # 将隐藏层输出组合成最终输出
    output = sum(w_hidden_output[i] * hidden_outputs[i] for i in range(4)) + b_output

    # 绘制三维图形
    fig = plt.figure(figsize=(10, 7))
    ax = fig.add_subplot(111, projection="3d")

    # 绘制输出的三维平面
    ax.plot_surface(x1, x2, output, cmap="viridis", alpha=0.7)

    # 添加决策平面（输出为 0.5 的等高线）
    ax.contour3D(x1, x2, output, levels=[0.5], colors="red")

    # 设置标签和标题
    ax.set_xlabel("x1")
    ax.set_ylabel("x2")
    ax.set_zlabel("Output")
    ax.set_title("3D Decision Boundary with 4 Hidden Nodes")

    plt.show()


if __name__ == "__main__":
    def rastrigin(x, y):
        A = 10
        return A * 2 + (x**2 - A * np.cos(2 * np.pi * x)) + (y**2 - A * np.cos(2 * np.pi * y))

    # 定义输入范围
    x = np.linspace(-5.12, 5.12, 400)
    y = np.linspace(-5.12, 5.12, 400)
    x, y = np.meshgrid(x, y)

    # 计算函数值
    z = rastrigin(x, y)

    # 绘制 3D 图像
    fig = plt.figure(figsize=(12, 8))
    ax = fig.add_subplot(111, projection='3d')
    ax.plot_surface(x, y, z, cmap='viridis', edgecolor='none', alpha=0.8)

    # 设置标签和标题
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_zlabel('f(x, y)')
    ax.set_title('Rastrigin Function')

    plt.show()